﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Utilities;
using Microsoft.SharePoint.WebPartPages;
using PS.Practices.SiteBuilder.Features.API;
using PS.Practices.SiteBuilder.Features.Schema;
using PS.Practices.SiteBuilder.Features.Schema.DOM;
using WebPart = PS.Practices.SiteBuilder.Features.Schema.DOM.WebPart;
using SysWebPart = System.Web.UI.WebControls.WebParts.WebPart;

namespace PS.Practices.Provisioner.Provisioner.Schema.Logic
{
    public class OmWebOperationVisitorHelpers
    {
        //TODO Remove execute/accept call from here
        //TODO Passing two SPList objects here
        public static void ProcessList(IListOperationVisitor visitor, List list, SPList spList)
        {
            #if !SANDBOX
            SPUtility.ValidateFormDigest();
            SPSecurity.RunWithElevatedPrivileges(delegate()
            {
#endif
                SPWeb web = spList.ParentWeb;

                web.AllowUnsafeUpdates = true;

                Logger.Info("Processing list " + spList.Title);

                if (list.Delete)
                {

                    spList.AllowDeletion = true;
                    spList.Update();
                    spList.Delete();
                    //web.Update();
                    Logger.Info("List deleted");
                    return;
                }

                if (!string.IsNullOrEmpty(list.EmailEnable))
                {
                    try
                    {
                        string alias = ParserUtil.ReplaceLiveFields(list.EmailEnable, spList, web);
                        spList.EmailAlias = alias;
                        spList.Update();

                        SPFolder folder = spList.RootFolder;
                        folder.Properties["vti_emailattachmentfolders"] = "root";
                        folder.Properties["vti_emailsaveoriginal"] = 1;
                        folder.Properties["vti_emailusesecurity"] = 1;

                        folder.Update();
                    }
                    catch (Exception ex)
                    {
                        Logger.Info("Error Email Enabling: " + list.Title);
                        Logger.Error(ex);
                        spList.EmailAlias = string.Empty;
                        web.AllowUnsafeUpdates = false;
                    }
                }
                if (!string.IsNullOrEmpty(list.MajorVersionLimit.ToString()) && list.MajorVersionLimit > 0)
                {
                    try
                    {
                        //string alias = ParserUtil.ReplaceLiveFields(EmailEnable, spList, web);
                        spList.EnableVersioning = true;
                        spList.MajorVersionLimit = list.MajorVersionLimit;
                        spList.Update();


                    }
                    catch (Exception ex)
                    {
                        Logger.Info("Error Email Enabling: " + list.Title);
                        Logger.Error(ex);
                        spList.EmailAlias = string.Empty;
                        web.AllowUnsafeUpdates = false;
                    }
                }
                if (!string.IsNullOrEmpty(list.MinorVersionLimit.ToString()) && list.MinorVersionLimit > 0)
                {
                    try
                    {
                        if (spList.EnableVersioning == false)
                            spList.EnableVersioning = true;
                        spList.EnableMinorVersions = true;
                        spList.MajorWithMinorVersionsLimit = list.MinorVersionLimit;
                        spList.Update();
                    }
                    catch (Exception ex)
                    {
                        Logger.Info("Error MinorVersionLimit: " + list.Title);
                        Logger.Error(ex);
                        spList.EmailAlias = string.Empty;
                    }
                }
                if (!string.IsNullOrEmpty(list.DraftSecurity))
                {
                    try
                    {
                        if (string.Compare(list.DraftSecurity, "any", true) == 0)
                        {
                            spList.DraftVersionVisibility = DraftVisibilityType.Reader;
                        }
                        if (string.Compare(list.DraftSecurity, "author", true) == 0)
                        {
                            spList.DraftVersionVisibility = DraftVisibilityType.Author;
                        }
                        spList.Update();
                    }
                    catch (Exception ex)
                    {
                        Logger.Info("Error DraftSecurity: " + list.Title);
                        Logger.Error(ex);
                        spList.EmailAlias = string.Empty;
                    }
                }
                try
                {
                    spList.ContentTypesEnabled = list.EnableContentTypes;
                    Logger.Info("Setting list attribute EnableContentTypes = " + list.EnableContentTypes);
                    spList.Update();
                }
                catch (Exception e)
                {
                    Logger.Info("Setting list attribute EnableContentTypes = " + e.Message);

                }

                // TODO remove accept
                foreach (ListOperation listOperation in list.Operations)
                {
                    listOperation.Accept(visitor);
                }

                web.AllowUnsafeUpdates = false;

#if !SANDBOX
            });
#endif
        }

        //TODO - Remove accept/execute from this
        public static void ProvisionWebs(IEnumerable<Web> nodes, SPWeb web, Dictionary<string, object> properties )
        {
            foreach (Web webNode in nodes)
            {
                if (string.IsNullOrEmpty(webNode.Title))
                {
                    Logger.Info("Required attribute Title is missing");
                    continue;
                }

                if (string.IsNullOrEmpty(webNode.Template))
                {
                    Logger.Info("Required attribute Template is missing");
                    continue;
                }

                if (string.IsNullOrEmpty(webNode.Url))
                {
                    Regex cleaner = new Regex(@"[\W]");
                    webNode.Url = cleaner.Replace(webNode.Title, "").ToLower(CultureInfo.InvariantCulture);
                }

                uint lcid = web.Language;
                if (!string.IsNullOrEmpty(webNode.LCID))
                {
                    uint.TryParse(webNode.LCID, out lcid);
                }


                Action<SPWeb> applyActions = w => { if (webNode.Actions.Enabled && webNode.Actions.Operations.Count > 0) ProvisionerRoot.Accept(new OmVisitorContext(w, properties), webNode.Actions.Operations);  };

                string weburl = webNode.Url;
                if (web.GetSubwebsForCurrentUser().Names.Any(url => string.Equals(url, weburl, StringComparison.OrdinalIgnoreCase)))
                {
                    var existingWeb = web.Webs[weburl];
                    if (webNode.InheritTopNav.HasValue && webNode.InheritTopNav.Value)
                    {
                        existingWeb.Navigation.UseShared = true;
                    }

                    existingWeb.Title = webNode.Title;
                    existingWeb.Description = webNode.Description;
                    existingWeb.Update();

                    if (webNode.UniquePermissions.HasValue)
                    {
                        if (existingWeb.HasUniqueRoleAssignments && !webNode.UniquePermissions.Value)
                            existingWeb.ResetRoleInheritance();
                        else if (!existingWeb.HasUniqueRoleAssignments && webNode.UniquePermissions.Value)
                        {
                            existingWeb.BreakRoleInheritance(true);
                        }
                    }

                    applyActions(existingWeb);

                    Logger.Info("Updated web: " + existingWeb.ServerRelativeUrl);


                    if (webNode.Webs != null && webNode.Webs.Count > 0)
                    {
                        ProvisionWebs(webNode.Webs, existingWeb, properties);
                    }
                }
                else
                {
                    SPWeb newWeb = null;
                    try
                    {
                        newWeb = web.Webs.Add(weburl, webNode.Title, webNode.Description, lcid,
                                            webNode.Template, webNode.UniquePermissions.HasValue && webNode.UniquePermissions.Value, false);
                    }
                    catch (Exception ex)
                    {
                        Logger.Error("Unable to create web: {0} under {1}\n{2}", weburl, web.ServerRelativeUrl, ex);
                        web.Webs.Delete(weburl);
                    }
                    if (newWeb != null)
                        using (newWeb)
                        {
                            Logger.Info("Created web: " + newWeb.ServerRelativeUrl);

                            if (webNode.InheritTopNav.HasValue && webNode.InheritTopNav.Value)
                            {
                                newWeb.Navigation.UseShared = true;
                                newWeb.Update();
                            }

                            applyActions(newWeb);

                            if (webNode.Webs != null && webNode.Webs.Count > 0)
                            {
                                ProvisionWebs(webNode.Webs, newWeb, properties);
                            }
                        }

                }
            }
        }

        public static bool FindWebPart(SPLimitedWebPartCollection webParts, WebPart webPart,
                                        out SysWebPart pageWebPart)
        {
            bool res = false;
            pageWebPart = null;
            foreach (SysWebPart part in webParts)
            {
                if (String.Compare(part.Title, webPart.Title, true) == 0)
                {
                    res = true;
                    pageWebPart = part;
                    break;
                }
            }
            return res;
        }

        public static void CreateGroup(SiteGroup siteGroup, SPWeb web)
        {
            Logger.Info("Creating cross site group: " + siteGroup.Name);

            PSGroup group = new PSGroup(siteGroup.Name, siteGroup.Description, web);

            @group.AllowMembersEditMembership = siteGroup.AllowMembersEditMembership;
            @group.AllowRequestToJoinLeave = siteGroup.AllowRequestToJoinLeave;
            @group.AutoAcceptRequestToJoinLeave = siteGroup.AutoAcceptRequestToJoinLeave;
            @group.OnlyAllowMembersViewMembership = siteGroup.OnlyAllowMembersViewMembership;
            @group.RequestToJoinLeaveEmailSetting = siteGroup.RequestToJoinLeaveEmailSetting;
            @group.SetOwner(siteGroup.Owner);
            @group.Update();

            //TODO: Check that this.Description can be null
        }


        public static void ProcessQuickLaunch(FixupWebACL acl, SPWeb web)
        {
            if (!String.IsNullOrEmpty(acl.SyncGroupQuickLaunch))
            {
                PSWebAcl webAcl = new PSWebAcl(web);
                switch (acl.SyncGroupQuickLaunch)
                {
                    case "False":
                    case "false":
                        return;

                    case "FromAssociations":
                    case "FromAllGroups":
                    case "True":
                    case "true":
                        {
                            webAcl.SyncGroupQuickLaunch(acl.SyncGroupQuickLaunch);
                            //Logger.Info("Syncing group quick launch");
                            //AclUtil.SyncGroupQuickLaunch(web, SyncGroupQuickLaunch == "FromAssociations");
                            break;
                        }

                    case "FromList":
                        {
                            //List<SPPrincipal> groups = new List<SPPrincipal>();
                            List<string> groups = new List<string>();
                            foreach (WebACLAction action in acl.Operations)
                            {
                                if (action is AssociateSiteGroup)
                                {
                                    AssociateSiteGroup siteGroup = (AssociateSiteGroup)action;

                                    if (!String.IsNullOrEmpty(siteGroup.AddToQuickLaunch))
                                    {
                                        bool addToQuickLaunch;
                                        if (Boolean.TryParse(siteGroup.AddToQuickLaunch, out addToQuickLaunch))
                                        {
                                            if (addToQuickLaunch)
                                            {
                                                groups.Add(siteGroup.Name);
                                            }
                                        }
                                    }
                                }
                            }


                            webAcl.SyncGroupQuickLaunch(groups);

                            break;
                        }
                }
            }
        }
    }
}
